package com.gyj.server.web;

import com.gyj.server.cluster.PeersReplicateBatch;
import com.gyj.server.cluster.PeersReplicator;
import com.gyj.server.core.*;
import com.gyj.server.entity.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Objects;


/**
 * 注册服务，接收client发送过来的请求
 * @author Gao
 * @date 2021/6/26
 */
public class RegisterServerController {

    private static final Logger logger = LogManager.getLogger(RegisterServerController.class);

    /**
     * 获取注册表实例单例
     */
    private ServiceRegistry registry = ServiceRegistry.getInstance();

    /**
     * 服务注册表的缓存
     */
    private ServiceRegistryCache registryCache = ServiceRegistryCache.getInstance();

    /**
     * 集群同步
     */
    private PeersReplicator peersReplicator = PeersReplicator.getInstance();

    /**
     * 服务接收客户端进行注册
     * @param request
     * @return
     */
    public RegisterResponse register(RegisterRequest request) {
        // 封装返回参数
        RegisterResponse response = new RegisterResponse();
        // 服务实例注册
        ServiceInstance instance = new ServiceInstance();
        instance.setServiceInstanceId(request.getServiceInstanceId());
        instance.setServiceName(request.getServiceName());
        instance.setHostName(request.getHostName());
        instance.setIp(request.getIp());
        instance.setPort(request.getPort());
        try {
            logger.info("服务接收客户端进行注册instance:{}", instance);
            // 服务注册加了写锁了，之前是用synchronized修饰
            registry.register(instance);

            // 更新自我保护机制心跳阈值
            synchronized (SelfProtectionPolicy.class) {
                SelfProtectionPolicy self = SelfProtectionPolicy.getInstance();
                self.setExpectedHeartbeatRate(self.getExpectedHeartbeatRate() + 2);
                self.setExpectedHeartbeatThreshold((long) (self.getExpectedHeartbeatRate() * 0.85));
            }

            // 过期掉注册表缓存
            registryCache.invalidate();

            // 注册服务集群同步
            peersReplicator.replicateRegister(request);

            response.setStatus(RegisterResponse.SUCCESS);
        } catch (Exception e) {
            logger.warn("服务接收客户端进行注册异常e:{}", e);
            response.setStatus(RegisterResponse.FAILURE);
        }
        return response;
    }

    /**
     * 发送心跳续约
     * @param request
     * @return
     */
    public HeartBeatResponse heartBeat(HeartbeatRequest request) {
        HeartBeatResponse response = new HeartBeatResponse();
        logger.info("服务端接收客户端心跳续约request:{}", request);
        ServiceInstance serviceInstance = registry.getServiceInstance(request.getServiceName(), request.getServiceInstanceId());
        logger.info("服务端接收客户端心跳续约, 获取相应的服务实例信息serviceInstance:{}", serviceInstance);
        if (Objects.isNull(serviceInstance)) {
            return null;
        }
        serviceInstance.renew();

        // 心跳次数统计，同时启动每分钟心跳次数清零的线程
        HeartBeatCounter heartBeatRate = HeartBeatCounter.getInstance();
        heartBeatRate.increment();

        // 发送心跳集群同步
        peersReplicator.replicateHeartbeat(request);

        response.setStatus(HeartBeatResponse.SUCCESS);
        return response;
    }

    /**
     * 同步batch数据
     * @param batch
     */
    public void replicateBatch(PeersReplicateBatch batch) {
        for(AbstractRequest request : batch.getRequests()) {
            // 服务注册
            if(request.getType().equals(AbstractRequest.REGISTER_REQUEST)) {
                register((RegisterRequest) request);
                // 服务下线
            } else if(request.getType().equals(AbstractRequest.CANCEL_REQUEST)) {
                cancel((CancelRequest) request);
                // 发送心跳
            } else if(request.getType().equals(AbstractRequest.HEARTBEAT_REQUEST)) {
                heartBeat((HeartbeatRequest) request);
            }
        }
    }

    /**
     * 拉取全量注册表
     * 之前通过synchronized和加读锁的方式优化
     * 现在可以直接通过从缓存中取数据
     * @return
     */
    public Applications fetchFullRegistry() {
        Applications applications = (Applications) registryCache.get(
                ServiceRegistryCache.CacheKey.FULL_SERVICE_REGISTRY);
        logger.info("拉取全量注册表, 获取返回结果applications:{}", applications);
        return applications;
    }

    /**
     * 拉取增量注册表
     * @return
     */
    public DeltaRegistry fetchDeltaRegistry() {
        DeltaRegistry deltaRegistry = (DeltaRegistry) registryCache.get(
                ServiceRegistryCache.CacheKey.DELTA_SERVICE_REGISTRY);
        logger.info("拉取增量注册表, 返回deltaRegistry:{}", deltaRegistry);
        return deltaRegistry;
    }

    /**
     * 服务下线
     * @param request
     */
    public void cancel(CancelRequest request) {
        // 服务下线加了写锁了，之前是用synchronized修饰
        registry.remove(request.getServiceName(), request.getServiceInstanceId());
        // 更新自我保护机制心跳阈值
        synchronized (SelfProtectionPolicy.class) {
            SelfProtectionPolicy self = SelfProtectionPolicy.getInstance();
            self.setExpectedHeartbeatRate(self.getExpectedHeartbeatRate() - 2);
            self.setExpectedHeartbeatThreshold((long) (self.getExpectedHeartbeatRate() * 0.85));
        }

        // 过期掉注册表缓存
        registryCache.invalidate();

        // 服务下线集群同步
        peersReplicator.replicateCancel(request);
    }

    // 拉取全量注册表（优化前）
    /*public Applications fetchServiceRegistry() {
        try {
            logger.info("[拉取全量注册表]加读锁");
            registry.readLock();
            Applications applications = new Applications();
            applications.setRegistry(registry.getRegistry());
            return applications;
        } finally {
            logger.info("[拉取全量注册表]释放读锁");
            registry.readUnlock();
        }
    }*/


    /**
     * 拉取增量注册表
     * @return
     */
    /*public DeltaRegistry fetchDeltaServiceRegistry() {
        try {
            logger.info("[拉取增量注册表]加读锁");
            registry.readLock();
            return registry.getDeltaRegistry();
        } finally {
            logger.info("[拉取增量注册表]释放读锁");
            registry.readUnlock();
        }
    }*/
}
